﻿namespace SPDeploy.Library.Processing.Processors
{
    using System;
    using Data;
    using Exceptions;
    using Helpers;
    using Library;
    using Microsoft.SharePoint;
    using Microsoft.SharePoint.Administration;
    using Action=SPDeploy.Data.Action;

    public class SiteProcessor : ProcessorBase<Site, SPSite>
    {
        #region Properties: public

        [ProcessorSetting(DefaultValue = IgnorableBehaviors.Ignore)]
        public IgnorableBehaviors AlreadyDeleted { get; set; }

        public override string Name
        {
            get { return "Site"; }
        }

        #endregion

        #region Methods: public

        public override SPSite Install(ProcessorContext ctx, Site config)
        {
            SPWebApplication webApp = GetParentApplication(ctx);
            Log(LogSeverity.Step, "{0} site '{1}' at '{2}' for web app '{3}'", config.Action, config.Title, config.Url, webApp.Name.IsEmpty() ? webApp.DefaultServerComment : webApp.Name);
            ValidateConfigurationContent(config);

            if (config.Action == Action.Lookup)
            {
                return FindExistingSiteOrThrow(config, webApp);
            }
            if (config.Action == Action.LookupOrCreate)
            {
                SPSite site = FindExistingSite(config, webApp);
                return site ?? CreateSite(config, webApp);
            }
            return CreateSite(config, webApp);
        }

        public override SPSite Uninstall(ProcessorContext ctx, Site config)
        {
            SPWebApplication webApp = GetParentApplication(ctx);
            Log(LogSeverity.Step, "{0} for site '{1}' at '{2}' for web app '{3}'", config.Action, config.Title, config.Url,
                webApp.Name.IsEmpty() ? webApp.DefaultServerComment : webApp.Name);
            ValidateConfigurationContent(config);

            if (config.Action == Action.Create)
            {
                SPSite site = FindExistingSite(config, webApp);
                if (site != null)
                {
                    site.Delete();
                }
                else if (AlreadyDeleted == IgnorableBehaviors.Error)
                {
                    throw new DeploymentTargetProcessorException(string.Format("Site could not be found with given guid ({0}) or url ({1})", config.Guid, config.Url));
                }
                ctx.ChildrenDeleted = true;
                return null;
            }

            // Action is Lookup or LookupOrCreate
            return FindExistingSiteOrThrow(config, webApp);
        }

        public override SPSite Update(ProcessorContext ctx, Site oldConfig, Site newConfig)
        {
            throw new NotImplementedException();
        }

        #endregion

        #region Methods: private

        private static SPSite CreateSite(Site config, SPWebApplication parentWebApp)
        {
            if (config.Title.IsEmpty() ||
                config.Template.IsEmpty() ||
                config.OwnerLogin.IsEmpty())
            {
                throw new DeploymentTargetConfigException("The fields Title, Template and OwnerLogin must all be defined for Site creation nodes");
            }
            return parentWebApp.Sites.Add(config.Url, config.Title, config.Description, (uint) config.LCID, config.Template, config.OwnerLogin, null, null, config.SecondaryOwnerLogin,
                                          null, null);
        }

        private static SPSite FindExistingSite(Site config, SPWebApplication parentWebApp)
        {
            SPSite site = null;
            if (!config.Guid.IsEmpty())
            {
                var guid = new Guid(config.Guid);
                foreach (SPSite siteIterator in parentWebApp.Sites)
                {
                    if (siteIterator.ID == guid)
                    {
                        site = siteIterator;
                        break;
                    }
                }
            }
            else
            {
                site = parentWebApp.Sites[config.Url];
            }
            return site;
        }

        private static SPSite FindExistingSiteOrThrow(Site config, SPWebApplication webApp)
        {
            SPSite site = FindExistingSite(config, webApp);
            if (site == null)
            {
                throw new DeploymentTargetProcessorException(string.Format("Site could not be found with given guid ({0}) or url ({1})", config.Guid, config.Url));
            }
            return site;
        }

        private static SPWebApplication GetParentApplication(ProcessorContext ctx)
        {
            var webApp = ctx.ParentResult as SPWebApplication;
            if (webApp == null)
            {
                throw new DeploymentTargetProcessorException("Site processor did not receive a valid web application instance");
            }
            return webApp;
        }

        private static void ValidateConfigurationContent(Site config)
        {
            if (config.Guid.IsEmpty() && config.Url.IsEmpty())
            {
                throw new DeploymentTargetConfigException("Guid and Url cannot both be empty for Site config nodes");
            }
        }

        #endregion
    }
}